
// Main header
#include "../Main.h"

//My Header
#include "Button.h"

//Fridge
#include "../Controller/Controller_Main.h"
#include "../Input.h"
#include "../MathsHelper.h"
#include "../TextureManager.h"
#include "../TextRender.h"
#include "../Timer.h"

static const u_int uBUTTON_BORDER_UP			= 0xAAAAAAFF;
static const u_int uBUTTON_BORDER_HOVER			= 0x888888FF;
static const u_int uBUTTON_BORDER_DOWN			= 0x000000FF;
static const u_int uBUTTON_BORDER_DISABLED		= 0xAAAAAAFF;

static const u_int uBUTTON_GRAD_START_UP		= 0xFFFFFFFF;
static const u_int uBUTTON_GRAD_START_HOVER		= 0xFAFAFAFF;
static const u_int uBUTTON_GRAD_START_DOWN		= 0xDDDDDDFF;
static const u_int uBUTTON_GRAD_START_DISABLED	= 0xF0F0F0FF;

static const u_int uBUTTON_GRAD_END_UP			= 0xF0F0F0FF;
static const u_int uBUTTON_GRAD_END_HOVER		= 0xBBBBBBFF;
static const u_int uBUTTON_GRAD_END_DOWN		= 0xDDDDDDFF;
static const u_int uBUTTON_GRAD_END_DISABLED	= 0xF0F0F0FF;

static const u_int uBUTTON_FLAT_TEXTCOLOUR_DISABLED	= 0xBBBBBBFF; 
static const u_int uBUTTON_FLAT_TEXTCOLOUR_UP		= 0x777777FF; 
static const u_int uBUTTON_FLAT_TEXTCOLOUR_HOVER	= 0x000000FF;
static const u_int uBUTTON_FLAT_BACKCOLOUR_UP		= 0xC7C7C700; 
static const u_int uBUTTON_FLAT_BACKCOLOUR_HOVER	= 0xC7C7C7FF; 

static const u_int uBUTTON_TEXT_ENABLED			= 0x000000FF;
static const u_int uBUTTON_TEXT_DISABLED		= 0x999999FF;

static const float fBUTTON_HOVER_SPEED			= 2.0f;

static const u_int uBUTTON_IMAGE_MARGIN			= 4;

Button::Button( Widget* pxParent ) : Widget( pxParent )
{
	m_pfnCallback = 0;
	m_pCallbackUserData = 0;
	m_bIsPressed = false;
	m_fHoverTimer = 0.0f;
	m_szText[0] = 0;
	m_bEnabled = true;
	m_xImage = INVALID_STRING_HASH;
	m_bRenderArrow = false;
	m_bFlatStyle = false;
	m_bCentreAlignText = true;
	m_fBorderWidth = 2.0f;
	m_uImageMargin = uBUTTON_IMAGE_MARGIN;
}

Button::~Button()
{
	delete [] (static_cast<char*>(m_pUserData));
}

void Button::Render ( )
{
	if( !m_bVisible )
	{
		return;
	}

	u_int uTextCol = 0;

	if( m_bFlatStyle )
	{
		u_int uBackCol = 0;

		glBindTexture( GL_TEXTURE_2D, INVALID_TEXTURE_ID );

		if( m_fHoverTimer > 0.0f )
		{
			uTextCol = MathsHelper::InterpolateColour( uBUTTON_FLAT_TEXTCOLOUR_UP, uBUTTON_FLAT_TEXTCOLOUR_HOVER, m_fHoverTimer );
			uBackCol = MathsHelper::InterpolateColour( uBUTTON_FLAT_BACKCOLOUR_UP, uBUTTON_FLAT_BACKCOLOUR_HOVER, m_fHoverTimer );
		}
		else
		{
			uTextCol = m_bEnabled ? uBUTTON_FLAT_TEXTCOLOUR_UP : uBUTTON_FLAT_TEXTCOLOUR_DISABLED;
			uBackCol = uBUTTON_FLAT_BACKCOLOUR_UP;
		}

		const u_int uSwappedBackCol = MathsHelper::RGBAtoABGR( uBackCol );
		glColor4ubv( reinterpret_cast<const GLubyte*>( &uSwappedBackCol ) );

		glBegin( GL_QUADS );

		glVertex2i( m_uPositionX, m_uPositionY );
		glVertex2i( m_uPositionX + m_uWidth, m_uPositionY );
		glVertex2i( m_uPositionX + m_uWidth, m_uPositionY + m_uHeight );
		glVertex2i( m_uPositionX, m_uPositionY + m_uHeight );

		glEnd();
	}
	else
	{
		uTextCol = uBUTTON_TEXT_ENABLED;

		u_int uBorderCol;
		u_int uGradStartCol;
		u_int uGradEndCol;

		if( !m_bEnabled )
		{
			uBorderCol		= uBUTTON_BORDER_DISABLED;
			uGradStartCol	= uBUTTON_GRAD_START_DISABLED;
			uGradEndCol		= uBUTTON_GRAD_END_DISABLED;
			uTextCol		= uBUTTON_TEXT_DISABLED;
		}
		else if( m_bIsPressed )
		{
			uBorderCol		= uBUTTON_BORDER_DOWN;
			uGradStartCol	= uBUTTON_GRAD_START_DOWN;
			uGradEndCol		= uBUTTON_GRAD_END_DOWN;
		}
		else
		{
			if( MouseInWidget() )
			{
				uBorderCol = uBUTTON_BORDER_HOVER;
			}
			else
			{
				uBorderCol = uBUTTON_BORDER_UP;
			}

			if( m_fHoverTimer > 0.0f )
			{
				uGradStartCol = MathsHelper::InterpolateColour( uBUTTON_GRAD_START_UP, uBUTTON_GRAD_START_HOVER, m_fHoverTimer );
				uGradEndCol = MathsHelper::InterpolateColour( uBUTTON_GRAD_END_UP, uBUTTON_GRAD_END_HOVER, m_fHoverTimer );
			}
			else
			{
				uGradStartCol = uBUTTON_GRAD_START_UP;
				uGradEndCol = uBUTTON_GRAD_END_UP;
			}
		}

		const float fPositionX = static_cast< float >( GetResizedX() );
		const float fPositionY = static_cast< float >( GetResizedY() );
		const float fWidth = static_cast< float >( GetResizedWidth() );
		const float fHeight = static_cast< float >( GetResizedHeight() );

		const u_int uSwappedCol1 = MathsHelper::RGBAtoABGR( uGradStartCol );
		const u_int uSwappedCol2 = MathsHelper::RGBAtoABGR( uGradEndCol );
	
		glEnable( GL_LINE_SMOOTH );
		glLineWidth( m_fBorderWidth );

		glBindTexture( GL_TEXTURE_2D, INVALID_TEXTURE_ID );

		// Render the background

		glBegin( GL_QUADS );

		glColor4ubv( reinterpret_cast<const GLubyte*>( &uSwappedCol1 ) );

		glVertex2f( fPositionX, fPositionY );
		glVertex2f( fPositionX + fWidth, fPositionY );
	
		glColor4ubv( reinterpret_cast<const GLubyte*>( &uSwappedCol2 ) );

		glVertex2f( fPositionX + fWidth, fPositionY + fHeight );
		glVertex2f( fPositionX, fPositionY + fHeight );

		glEnd();

		// Render the border

		const u_int uSwappedCol = MathsHelper::RGBAtoABGR( uBorderCol );

		glColor4ubv( reinterpret_cast<const GLubyte*>( &uSwappedCol ) );

		glBegin( GL_LINE_LOOP );

		// Top
		// glVertex2f( fPositionX, fPositionY );
		glVertex2f( fPositionX + fWidth, fPositionY );

		// Right
		// glVertex2f( fPositionX + fWidth, fPositionY );
		glVertex2f( fPositionX + fWidth, fPositionY + fHeight );

		// Bottom
		// glVertex2f( fPositionX + fWidth , fPositionY + fHeight );
		glVertex2f( fPositionX, fPositionY + fHeight );

		// Left
		// glVertex2f( fPositionX, fPositionY + fHeight );
		glVertex2f( fPositionX, fPositionY );


		glEnd( );
	}

	// Render the text;

	if( m_szText[0] )
	{
		TextRender::SetColour( uTextCol );
		TextRender::SetFont( FONT_SANS_12 );
		
		u_int uTextHeight, uTextWidth;
		TextRender::GetRenderSize( m_szText, uTextWidth, uTextHeight );
			
		if( m_bCentreAlignText )
		{
			TextRender::Print( m_szText, GetResizedX() + GetResizedWidth() / 2 - uTextWidth / 2, GetResizedY() + GetResizedHeight() / 2 - uTextHeight / 2 );
		}
		else
		{
			TextRender::Print( m_szText, GetResizedX() + uBUTTON_HORZ_TEXT_MARGIN, GetResizedY() + GetResizedHeight() / 2 - uTextHeight / 2 );
		}
	}

	// render the image

	if( m_xImage != INVALID_STRING_HASH )
	{
		TextureManager* pxTextureManager = Controller_Main::GetTextureManager();
		
		if( pxTextureManager )
		{
			int iTextureID = pxTextureManager->GetTextureID( m_xImage );
			
			glColor4f( 1.0f, 1.0f, 1.0f, 1.0f );
			glBindTexture( GL_TEXTURE_2D, iTextureID );

			float fWidth = GetResizedWidth() - static_cast<float>( m_uImageMargin * 2 );
			float fHeight = GetResizedHeight() - static_cast<float>( m_uImageMargin * 2 );
			float fSize = 0.0f;
			if( fWidth > fHeight )
			{
				fSize = fHeight;
			}
			else
			{
				fSize = fWidth;
			}
			const float fCentreX = floorf( GetResizedX() + GetResizedWidth() * 0.5f );
			const float fCentreY = floorf( GetResizedY() + GetResizedHeight() * 0.5f );
			const float fHalfSize = floorf( fSize * 0.5f );

			glBegin( GL_QUADS );

			glTexCoord2f( 0.0f, 0.0f );
			glVertex2f( fCentreX - fHalfSize, fCentreY - fHalfSize );
			glTexCoord2f( 0.0f, 1.0f );
			glVertex2f( fCentreX - fHalfSize, fCentreY + fHalfSize );
			glTexCoord2f( 1.0f, 1.0f );
			glVertex2f( fCentreX + fHalfSize, fCentreY + fHalfSize );
			glTexCoord2f( 1.0f, 0.0f );
			glVertex2f( fCentreX + fHalfSize, fCentreY - fHalfSize );

			glEnd();
		}
	}

	// Render an arrow if required

	if( m_bRenderArrow )
	{
		glBindTexture( GL_TEXTURE_2D, INVALID_TEXTURE_ID );

		const u_int uSwappedCol = MathsHelper::RGBAtoABGR( uTextCol );

		glColor4ubv( reinterpret_cast<const GLubyte*>( &uSwappedCol ) );

		const int iCentreX = static_cast<int>( m_uPositionX + m_uWidth - 8 );
		const int iCentreY = static_cast<int>( m_uPositionY + m_uHeight / 2 );

		glBegin( GL_TRIANGLES );

		glVertex2i( iCentreX - 4, iCentreY - 4 ); 
		glVertex2i( iCentreX - 4, iCentreY + 4 );
		glVertex2i( iCentreX + 4, iCentreY );

		glEnd();
	}

	Widget::Render();
}

void Button::Update	()
{
	const Input* pxInputHandler = Controller_Main::GetInputHandler();

	if( MouseInWidget() && m_bEnabled )
	{
		if( pxInputHandler->MouseButtonPressed( INPUT_MOUSE_BUTTON_LEFT ) )
		{
			m_bIsPressed = true;
		}
		else if( pxInputHandler->MouseButtonReleased( INPUT_MOUSE_BUTTON_LEFT ) && m_bIsPressed )
		{
			if( m_pfnCallback )
			{
				m_pfnCallback( m_pCallbackUserData );
			}
		}

		m_fHoverTimer += Timer::GetFrameTime() * fBUTTON_HOVER_SPEED;
		if( m_fHoverTimer > 1.0f )
		{
			m_fHoverTimer = 1.0f;
		}
	}
	else
	{
		m_fHoverTimer -= Timer::GetFrameTime() * fBUTTON_HOVER_SPEED;
		if( m_fHoverTimer < 0.0f )
		{
			m_fHoverTimer = 0.0f;
		}
	}
	
	if( pxInputHandler->MouseButtonReleased( INPUT_MOUSE_BUTTON_LEFT ) )
	{
		m_bIsPressed = false;
	}

	Widget::Update();
}

void Button::SetButtonPressCallback( ButtonPressCallback pfnCallback, void* pCallbackUserData )
{
	m_pfnCallback = pfnCallback;
	m_pCallbackUserData = pCallbackUserData;
}

void Button::SetLabel ( const char* szText )
{
	strncpy( m_szText, szText, 64 );
	m_xImage = 0;
}

void Button::SetImage( const StringHash xHash )
{
	m_xImage = xHash;
	m_szText[0] = 0;
}

void Button::SetEnabled ( const bool bEnabled )
{
	if( bEnabled == m_bEnabled )
	{
		return;
	}

	m_bEnabled = bEnabled;

	if( !m_bEnabled )
	{
		m_fHoverTimer = 0.0f;
		m_bIsPressed = false;
	}
}

//eof
